package com.mjlf.framework.util;

import com.mjlf.framework.aop.AdviseUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @auther a123
 * @create 2018-08-25 15:47
 * @desc 类帮助器， 该该类中会加载系统中指定包下的所有类， 同时提供一些工具类
 * 在实例化该类之前， 必须先执行ConfigUtil加载配置信息
 */
public final class ClassManager {

    private static Set<Class<?>> CLASS_SET;

    public static void init() {
        String scanPackagePath = (String) ConfigUtil.getValue("scan.package.base");
        CLASS_SET = ClassUtil.getClassSet(scanPackagePath);
    }

    /**
     * 获取指定注解类型的类
     *
     * @param annotationClass
     * @return
     */
    public static Set<Class<?>> getClassSet(Class annotationClass) {
        if (annotationClass == null) {
            return CLASS_SET;
        } else {
            Set<Class<?>> classSet = new HashSet<>();
            for (Class<?> cls : CLASS_SET) {
                if (getAnn(cls, annotationClass, null) != null
                        && !cls.isAnnotation()
                        && !cls.isInterface()) {
                    classSet.add(cls);
                }
            }
            return classSet;
        }
    }

    /**
     * 判断在cls类上是否标注了annotationClass注解
     * @param cls
     * @param annotationClass
     * @param stack
     * @return
     */
    public static Annotation getAnn(Class<?> cls, Class annotationClass, Stack stack) {
        if (cls.isAnnotationPresent(annotationClass)) {
            return cls.getAnnotation(annotationClass);
        }
        if (stack == null) {
            stack = new Stack();
        }
        if(stack.contains(cls)){
            return null;
        }
        stack.push(cls);
        try {
            Annotation[] annotations = cls.getDeclaredAnnotations();
            if (annotations != null) {
                for (Annotation annotation : annotations) {
                    if (annotation.annotationType().isAnnotationPresent(annotationClass)) {
                        return annotation.annotationType().getAnnotation(annotationClass);
                    } else {
                        return getAnn(annotation.annotationType(), annotationClass, stack);
                    }
                }
            }
        } catch (Exception e) {
            throw e;
        }finally {
            stack.pop();
        }
        return null;
    }

    public static  boolean needProxy(Class<?> cls){
        if(cls != null){
            List<Method> methods = Arrays.asList(cls.getDeclaredMethods());
            for(Method method : methods){
                if(AdviseUtil.needProxy(method)){
                    return true;
                }
            }
            return false;
        }
        return false;
    }
}
